from abc import ABC, abstractmethod
from typing import Optional, List, Dict, Any, Type, Union
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, update, delete, func, and_, or_
from sqlalchemy.orm import selectinload
from src.common.db.database import get_db_session
from src.models.base import BaseModel
from loguru import logger

class BaseRepository(ABC):
    """仓储层基类"""
    
    def __init__(self, model_class: Type[BaseModel]):
        self.model_class = model_class
    
    async def get_by_id(self, id: Union[int, str], include_deleted: bool = False) -> Optional[Dict[str, Any]]:
        """根据ID获取记录
        
        Args:
            id: 记录ID（支持雪花算法生成的大整数）
            include_deleted: 是否包含已删除的记录
            
        Returns:
            记录字典或None
        """
        async with get_db_session() as session:
            query = select(self.model_class).where(self.model_class.id == id)
            
            if not include_deleted:
                query = query.where(self.model_class.status == 1)
            
            result = await session.execute(query)
            instance = result.scalar_one_or_none()
            
            return instance.to_dict() if instance else None
    
    async def get_by_ids(self, ids: List[Union[int, str]], include_deleted: bool = False) -> List[Dict[str, Any]]:
        """根据ID列表批量获取记录"""
        if not ids:
            return []
            
        async with get_db_session() as session:
            query = select(self.model_class).where(self.model_class.id.in_(ids))
            
            if not include_deleted:
                query = query.where(self.model_class.status == 1)
            
            result = await session.execute(query)
            instances = result.scalars().all()
            
            return [instance.to_dict() for instance in instances]
    
    async def create(self, data: Dict[str, Any]) -> Dict[str, Any]:
        """创建记录
        
        Args:
            data: 要创建的数据字典
            
        Returns:
            创建的记录字典
        """
        async with get_db_session() as session:
            try:
                instance = self.model_class(**data)
                session.add(instance)
                await session.commit()
                await session.refresh(instance)
                
                logger.info(f"创建{self.model_class.__name__}记录成功: ID={instance.id}")
                return instance.to_dict()
                
            except Exception as e:
                await session.rollback()
                logger.error(f"创建{self.model_class.__name__}记录失败: {str(e)}")
                raise
    
    async def batch_create(self, data_list: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """批量创建记录"""
        if not data_list:
            return []
            
        async with get_db_session() as session:
            try:
                instances = [self.model_class(**data) for data in data_list]
                session.add_all(instances)
                await session.commit()
                
                # 刷新所有实例以获取生成的ID
                for instance in instances:
                    await session.refresh(instance)
                
                logger.info(f"批量创建{self.model_class.__name__}记录成功: 数量={len(instances)}")
                return [instance.to_dict() for instance in instances]
                
            except Exception as e:
                await session.rollback()
                logger.error(f"批量创建{self.model_class.__name__}记录失败: {str(e)}")
                raise
    
    async def update(self, id: Union[int, str], data: Dict[str, Any]) -> bool:
        """更新记录
        
        Args:
            id: 记录ID（支持雪花算法生成的大整数）
            data: 要更新的数据字典
            
        Returns:
            是否更新成功
        """
        async with get_db_session() as session:
            try:
                # 先查询记录是否存在
                query = select(self.model_class).where(
                    and_(self.model_class.id == id, self.model_class.status == 1)
                )
                result = await session.execute(query)
                instance = result.scalar_one_or_none()
                
                if not instance:
                    return False
                
                # 更新字段
                instance.update_from_dict(data)
                await session.commit()
                
                logger.info(f"更新{self.model_class.__name__}记录成功: ID={id}")
                return True
                
            except Exception as e:
                await session.rollback()
                logger.error(f"更新{self.model_class.__name__}记录失败: ID={id}, 错误={str(e)}")
                raise
    
    async def delete(self, id: Union[int, str], hard_delete: bool = False, user_id: str = None) -> bool:
        """删除记录
        
        Args:
            id: 记录ID（支持雪花算法生成的大整数）
            hard_delete: 是否硬删除
            user_id: 操作用户ID
            
        Returns:
            是否删除成功
        """
        async with get_db_session() as session:
            try:
                query = select(self.model_class).where(self.model_class.id == id)
                result = await session.execute(query)
                instance = result.scalar_one_or_none()
                
                if not instance:
                    return False
                
                if hard_delete:
                    await session.delete(instance)
                else:
                    instance.soft_delete(user_id)
                
                await session.commit()
                
                delete_type = "硬删除" if hard_delete else "软删除"
                logger.info(f"{delete_type}{self.model_class.__name__}记录成功: ID={id}")
                return True
                
            except Exception as e:
                await session.rollback()
                logger.error(f"删除{self.model_class.__name__}记录失败: ID={id}, 错误={str(e)}")
                raise
    
    async def batch_delete(self, ids: List[Union[int, str]], hard_delete: bool = False, user_id: str = None) -> int:
        """批量删除记录
        
        Returns:
            删除的记录数量
        """
        if not ids:
            return 0
            
        async with get_db_session() as session:
            try:
                if hard_delete:
                    query = delete(self.model_class).where(self.model_class.id.in_(ids))
                    result = await session.execute(query)
                    deleted_count = result.rowcount
                else:
                    # 软删除
                    update_data = {'status': 0}
                    if user_id:
                        update_data['update_user'] = user_id
                    
                    query = update(self.model_class).where(
                        self.model_class.id.in_(ids)
                    ).values(**update_data)
                    result = await session.execute(query)
                    deleted_count = result.rowcount
                
                await session.commit()
                
                delete_type = "硬删除" if hard_delete else "软删除"
                logger.info(f"批量{delete_type}{self.model_class.__name__}记录成功: 数量={deleted_count}")
                return deleted_count
                
            except Exception as e:
                await session.rollback()
                logger.error(f"批量删除{self.model_class.__name__}记录失败: {str(e)}")
                raise
    
    async def count(self, filters: Dict[str, Any] = None, include_deleted: bool = False) -> int:
        """统计记录数量
        
        Args:
            filters: 过滤条件
            include_deleted: 是否包含已删除的记录
            
        Returns:
            记录数量
        """
        async with get_db_session() as session:
            query = select(func.count(self.model_class.id))
            
            # 添加状态过滤
            if not include_deleted:
                query = query.where(self.model_class.status == 1)
            
            # 添加其他过滤条件
            if filters:
                query = self._apply_filters(query, filters)
            
            result = await session.execute(query)
            return result.scalar()
    
    async def exists(self, filters: Dict[str, Any], include_deleted: bool = False) -> bool:
        """检查记录是否存在"""
        count = await self.count(filters, include_deleted)
        return count > 0
    
    async def list_all(self, filters: Dict[str, Any] = None, 
                      order_by: str = None, include_deleted: bool = False) -> List[Dict[str, Any]]:
        """获取所有记录
        
        Args:
            filters: 过滤条件
            order_by: 排序字段
            include_deleted: 是否包含已删除的记录
            
        Returns:
            记录列表
        """
        async with get_db_session() as session:
            query = select(self.model_class)
            
            # 添加状态过滤
            if not include_deleted:
                query = query.where(self.model_class.status == 1)
            
            # 添加其他过滤条件
            if filters:
                query = self._apply_filters(query, filters)
            
            # 添加排序
            if order_by:
                query = self._apply_order_by(query, order_by)
            
            result = await session.execute(query)
            instances = result.scalars().all()
            
            return [instance.to_dict() for instance in instances]
    
    async def paginate(self, page: int = 1, size: int = 20, 
                      filters: Dict[str, Any] = None, order_by: str = None,
                      include_deleted: bool = False) -> Dict[str, Any]:
        """分页查询
        
        Args:
            page: 页码（从1开始）
            size: 每页大小
            filters: 过滤条件
            order_by: 排序字段
            include_deleted: 是否包含已删除的记录
            
        Returns:
            分页结果字典
        """
        # 参数验证
        page = max(1, page)
        size = max(1, min(100, size))  # 限制最大每页100条
        
        async with get_db_session() as session:
            # 构建基础查询
            query = select(self.model_class)
            
            # 添加状态过滤
            if not include_deleted:
                query = query.where(self.model_class.status == 1)
            
            # 添加其他过滤条件
            if filters:
                query = self._apply_filters(query, filters)
            
            # 统计总数
            count_query = select(func.count()).select_from(query.subquery())
            total_result = await session.execute(count_query)
            total = total_result.scalar()
            
            # 添加排序
            if order_by:
                query = self._apply_order_by(query, order_by)
            
            # 添加分页
            offset = (page - 1) * size
            query = query.offset(offset).limit(size)
            
            # 执行查询
            result = await session.execute(query)
            instances = result.scalars().all()
            
            return {
                'total': total,
                'page': page,
                'size': size,
                'pages': (total + size - 1) // size,  # 总页数
                'data': [instance.to_dict() for instance in instances]
            }
    
    def _apply_filters(self, query, filters: Dict[str, Any]):
        """应用过滤条件"""
        for field, value in filters.items():
            if hasattr(self.model_class, field):
                column = getattr(self.model_class, field)
                
                if isinstance(value, dict):
                    # 支持操作符过滤，如 {'age': {'gte': 18, 'lt': 65}}
                    for op, val in value.items():
                        if op == 'eq':
                            query = query.where(column == val)
                        elif op == 'ne':
                            query = query.where(column != val)
                        elif op == 'gt':
                            query = query.where(column > val)
                        elif op == 'gte':
                            query = query.where(column >= val)
                        elif op == 'lt':
                            query = query.where(column < val)
                        elif op == 'lte':
                            query = query.where(column <= val)
                        elif op == 'like':
                            query = query.where(column.like(f'%{val}%'))
                        elif op == 'in':
                            query = query.where(column.in_(val))
                        elif op == 'not_in':
                            query = query.where(~column.in_(val))
                elif isinstance(value, list):
                    # 列表值使用 IN 操作
                    query = query.where(column.in_(value))
                else:
                    # 简单相等比较
                    query = query.where(column == value)
        
        return query
    
    def _apply_order_by(self, query, order_by: str):
        """应用排序"""
        if order_by.startswith('-'):
            # 降序
            field = order_by[1:]
            if hasattr(self.model_class, field):
                column = getattr(self.model_class, field)
                query = query.order_by(column.desc())
        else:
            # 升序
            if hasattr(self.model_class, order_by):
                column = getattr(self.model_class, order_by)
                query = query.order_by(column.asc())
        
        return query